#include "StdAfx.h"
#include "QuadTreeDemoState.h"

#include "CoreEngine.h"
#include "MainState.h"


namespace
{
	float BLOCK_SIZE = 1.5f;
}

QuadTreeDemoState::QuadTreeDemoState()
	: FEApplication(), FEngine::KeyboardInputListener(), FEngine::MouseInputListener()
{
	mCameraHandler		= NULL;
	mStatPanel			= NULL;
	mCenterLine			= NULL;
	mQuadTreeManager	= NULL;
	mAABBLine			= NULL;
}

QuadTreeDemoState::~QuadTreeDemoState()
{
	FEngine::InputManager::getInstance()->unregisterKeyboardInputListener(this);
	FEngine::InputManager::getInstance()->unregisterMouseInputListener(this);
	
	delete mCameraHandler;
	delete mStatPanel;
	if (mCenterLine)
		delete mCenterLine;
	
	for (std::list<FEngine::TextLabel*>::iterator it = mListLabels.begin(); it != mListLabels.end(); ++it)
		delete *it;
	
	for (std::list<FEngine::PrimitiveLineList*>::iterator it = mListLines.begin(); it != mListLines.end(); ++it)
		delete *it;
	
	for (std::list<FEngine::PrimitiveCube*>::iterator it = mListCubes.begin(); it != mListCubes.end(); ++it)
		delete *it;

	if (mQuadTreeManager)
		delete mQuadTreeManager;

	if (mAABBLine)
		delete mAABBLine;
}

void QuadTreeDemoState::initialize()
{
	FEngine::FEApplication::initialize();
	FEngine::InputManager::getInstance()->registerKeyboardInputListener(this);
	FEngine::InputManager::getInstance()->registerMouseInputListener(this);

	FEngine::CoreEngine::getInstance()->getCamera()->setFarDistanceView(1500.0f);

	mCameraHandler = new FEngine::FreeCameraHandler(FEngine::CoreEngine::getInstance()->getCamera(), Vector3(0, 50, -100), Vector3(0, 0, 1));
	addChild(mCameraHandler);
	
	FEngine::CoreEngine::getInstance()->disableFog();
	
	FEngine::CoreEngine::getInstance()->setSkyDome("skydome1.dds", 1.0f);

	mStatPanel = new StatPanel();
	addGUIElement(mStatPanel);

	
	mListLabels.push_back(new FEngine::TextLabel("This show the structure of the quad tree", 350, 10, 0, 200, 22, FEngine::ColorRGB(255, 255, 255)));
	addGUIElement(mListLabels.back());
	mListLabels.push_back(new FEngine::TextLabel("Each square represents one node", 350, 40, 0, 200, 22, FEngine::ColorRGB(255, 255, 255)));
	addGUIElement(mListLabels.back());
	mListLabels.push_back(new FEngine::TextLabel("The green squares are the smallest squares the tree can have, containing the scene objects", 350, 70, 0, 200, 22, FEngine::ColorRGB(255, 255, 255)));
	addGUIElement(mListLabels.back());
	mListLabels.push_back(new FEngine::TextLabel("Press SPACE to place an object under the position of the camera (y = 0)", 350, 100, 0, 200, 22, FEngine::ColorRGB(255, 255, 255)));
	addGUIElement(mListLabels.back());


	mCenterLine = new FEngine::PrimitiveLineList();
	mCenterLine->addLine(Vector3(-1000, 0, 0), Vector3(1000, 0, 0));
	mCenterLine->addLine(Vector3(0, 0, -1000), Vector3(0, 0, 1000));
	mCenterLine->generate();
	mCenterLine->setColor(0, 0, 255);
	addChild(mCenterLine);
	
	mQuadTreeManager = new FEngine::QuadTreeManager(BLOCK_SIZE);
}

void QuadTreeDemoState::update(double _elapsedTime)
{
	FEApplication::update(_elapsedTime);
}

void QuadTreeDemoState::updateGUI(double _elapsedTime)
{
	FEApplication::updateGUI(_elapsedTime);
}


void QuadTreeDemoState::render(double _elapsedTime)
{
	FEApplication::render(_elapsedTime);
}

void QuadTreeDemoState::keyPressed(int _key)
{
	if (_key == FEngine::InputManager::KEY_SPACE)
		_placeNewObject(Vector3(FEngine::CoreEngine::getInstance()->getCamera()->getPosition()));

	if (_key == FEngine::InputManager::KEY_ESCAPE)
		FEngine::CoreEngine::getInstance()->setApplication(new MainState());
}

void QuadTreeDemoState::keyReleased(int _key)
{
}

void QuadTreeDemoState::mouseButtonPressed(int _button, const Vector2& _position)
{
}

void QuadTreeDemoState::mouseButtonReleased(int _button, const Vector2& _position)
{
}

void QuadTreeDemoState::mouseMoved(const Vector2& _delta)
{
}

void QuadTreeDemoState::_placeNewObject(const Vector3& _pos)
{
	for (std::list<FEngine::PrimitiveLineList*>::iterator it = mListLines.begin(); it != mListLines.end(); ++it)
		delete *it;
	mListLines.clear();
	delete mAABBLine;
	
	mQuadTreeManager->getNodeByPosition(Vector2(_pos.x, _pos.z), new FEngine::QuadTreeNode(BLOCK_SIZE));
	
	// Recreate the square
	std::list<FEngine::QuadTreeNode*> fourChildNode = mQuadTreeManager->getChildNode();
	std::list<FEngine::QuadTreeNode*> listNode;
	for (std::list<FEngine::QuadTreeNode*>::iterator it = fourChildNode.begin(); it != fourChildNode.end(); ++it)
	{
		listNode = _getChildList(*it);
		for (std::list<FEngine::QuadTreeNode*>::iterator it = listNode .begin(); it != listNode .end(); ++it)
		{
			mListLines.push_back(_createLine(*it));
			addChild(mListLines.back());
		}
	}
	
	// Create the AABB node
	Vector3 minPos = mQuadTreeManager->getAABB()->getMinPoint();
	Vector3 maxPos = mQuadTreeManager->getAABB()->getMaxPoint();
	mAABBLine = new FEngine::PrimitiveLineList();
	mAABBLine->addLine(Vector3(minPos.x, 0, minPos.z), Vector3(minPos.x, 0, maxPos.z));
	mAABBLine->addLine(Vector3(minPos.x, 0, maxPos.z), Vector3(maxPos.x, 0, maxPos.z));
	mAABBLine->addLine(Vector3(maxPos.x, 0, maxPos.z), Vector3(maxPos.x, 0, minPos.z));
	mAABBLine->addLine(Vector3(maxPos.x, 0, minPos.z), Vector3(minPos.x, 0, minPos.z));
	mAABBLine->generate();
	mAABBLine->setColor(255, 255, 0);
	addChild(mAABBLine);
	
	// Add a cube to represent one object
	FEngine::PrimitiveCube* cube = new FEngine::PrimitiveCube(0.1f);
	cube->setPosition(_pos.x, 0, _pos.z);
	cube->setColor(0, 255, 255);
	addChild(cube);
	mListCubes.push_back(cube);
}

FEngine::PrimitiveLineList* QuadTreeDemoState::_createLine(FEngine::QuadTreeNode* _node)
{
	Vector3 minPos = _node->getAABB()->getMinPoint();
	Vector3 maxPos = _node->getAABB()->getMaxPoint();

	float height = _node->getInversedDeep() * 0.05f;

	FEngine::PrimitiveLineList* line;
	line = new FEngine::PrimitiveLineList();
	line->addLine(Vector3(minPos.x, height, minPos.z), Vector3(minPos.x, height, maxPos.z));
	line->addLine(Vector3(minPos.x, height, maxPos.z), Vector3(maxPos.x, height, maxPos.z));
	line->addLine(Vector3(maxPos.x, height, maxPos.z), Vector3(maxPos.x, height, minPos.z));
	line->addLine(Vector3(maxPos.x, height, minPos.z), Vector3(minPos.x, height, minPos.z));
	line->generate();

	if (_node->getSize() == BLOCK_SIZE)
		line->setColor(0, 255, 0);

	return line;
}

std::list<FEngine::QuadTreeNode*> QuadTreeDemoState::_getChildList(FEngine::QuadTreeNode* _node)
{
	std::list<FEngine::QuadTreeNode*> listChild;
	std::list<FEngine::QuadTreeNode*> listNode;
	std::list<FEngine::QuadTreeNode*> listNodeChild;

	listChild = _node->getChildren();
	
	for (std::list<FEngine::QuadTreeNode*>::iterator it = listChild.begin(); it != listChild.end(); ++it)
	{
		listNodeChild = _getChildList((*it));
		for (std::list<FEngine::QuadTreeNode*>::iterator it2 = listNodeChild.begin(); it2 != listNodeChild.end(); ++it2)
			listNode.push_back(*it2);
	}

	listNode.push_back(_node);

	return listNode;
}
